﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
using Microsoft.Win32;

namespace WpfApp1
{
    /// <summary>
    /// 文件夹备份监控工具主窗口
    /// </summary>
    public partial class MainWindow : Window
    {
        private readonly BackupService _backupService;
        private CancellationTokenSource _cancellationTokenSource;
        private bool _isBackupRunning = false;

        public MainWindow()
        {
            InitializeComponent();

            _backupService = new BackupService();
            _backupService.ProgressUpdated += OnProgressUpdated;
            _backupService.StatusChanged += OnStatusChanged;

            TaskListView.ItemsSource = _backupService.BackupTasks;
            UpdateButtonStates();
        }

        private void UpdateButtonStates()
        {
            StartButton.IsEnabled = !string.IsNullOrEmpty(SourcePathTextBox.Text) &&
                                  !string.IsNullOrEmpty(TargetPathTextBox.Text) &&
                                  !_isBackupRunning;

            StopButton.IsEnabled = _isBackupRunning;
        }

        private void SelectSourceFolderButton_Click(object sender, RoutedEventArgs e)
        {
            var dialog = new OpenFileDialog
            {
                CheckFileExists = false,
                CheckPathExists = true,
                FileName = "选择文件夹",
                Filter = "文件夹|*.",
                ValidateNames = false
            };

            if (dialog.ShowDialog() == true)
            {
                SourcePathTextBox.Text = Path.GetDirectoryName(dialog.FileName);
                UpdateButtonStates();
            }
        }

        private void SelectTargetFolderButton_Click(object sender, RoutedEventArgs e)
        {
            var dialog = new OpenFileDialog
            {
                CheckFileExists = false,
                CheckPathExists = true,
                FileName = "选择文件夹",
                Filter = "文件夹|*.",
                ValidateNames = false
            };

            if (dialog.ShowDialog() == true)
            {
                TargetPathTextBox.Text = Path.GetDirectoryName(dialog.FileName);
                UpdateButtonStates();
            }
        }

        private async void StartButton_Click(object sender, RoutedEventArgs e)
        {
            if (_isBackupRunning) return;

            _backupService.ClearTasks();
            _isBackupRunning = true;
            UpdateButtonStates();

            _cancellationTokenSource = new CancellationTokenSource();

            try
            {
                StatusTextBlock.Content = "开始备份...";
                await _backupService.PerformBackupAsync(
                    SourcePathTextBox.Text,
                    TargetPathTextBox.Text,
                    _cancellationTokenSource.Token);

                StatusTextBlock.Content = "备份完成";
            }
            catch (OperationCanceledException)
            {
                StatusTextBlock.Content = "备份已取消";
            }
            catch (Exception ex)
            {
                StatusTextBlock.Content = $"备份出错: {ex.Message}";
            }
            finally
            {
                _isBackupRunning = false;
                UpdateButtonStates();
            }
        }

        private void StopButton_Click(object sender, RoutedEventArgs e)
        {
            _cancellationTokenSource?.Cancel();
            StatusTextBlock.Content = "正在停止备份...";
        }

        private void OnProgressUpdated(object sender, EventArgs e)
        {
            Dispatcher.Invoke(() =>
            {
                TaskListView.Items.Refresh();

                double totalSpeed = 0;
                foreach (var task in _backupService.BackupTasks)
                {
                    if (task.Status == BackupStatus.InProgress)
                    {
                        totalSpeed += task.GetTransferSpeed();
                    }
                }

                SpeedTextBlock.Content = $"{totalSpeed:F2} KB/s";
            });
        }

        private void OnStatusChanged(object sender, string e)
        {
            Dispatcher.Invoke(() =>
            {
                StatusTextBlock.Content = e;
            });
        }
    }

    /// <summary>
    /// 备份服务类，处理所有备份逻辑
    /// </summary>
    public class BackupService
    {
        private const int MinimumFileAgeSeconds = 300; // 5分钟

        public event EventHandler ProgressUpdated;
        public event EventHandler<string> StatusChanged;

        public List<BackupTask> BackupTasks { get; } = new List<BackupTask>();

        public void ClearTasks()
        {
            BackupTasks.Clear();
            OnProgressUpdated();
        }

        public async Task PerformBackupAsync(string sourcePath, string targetPath, CancellationToken cancellationToken)
        {
            if (string.IsNullOrEmpty(sourcePath) || string.IsNullOrEmpty(targetPath))
                throw new ArgumentException("源路径和目标路径不能为空");

            if (!Directory.Exists(sourcePath))
                throw new DirectoryNotFoundException($"源目录不存在: {sourcePath}");

            // 确保目标文件夹存在
            if (!Directory.Exists(targetPath))
            {
                Directory.CreateDirectory(targetPath);
                OnStatusChanged($"创建目标目录: {targetPath}");
            }

            // 递归备份文件夹
            await BackupDirectoryAsync(sourcePath, targetPath, cancellationToken);
        }

        private async Task BackupDirectoryAsync(string sourceDir, string targetDir, CancellationToken cancellationToken)
        {
            try
            {
                // 获取所有子目录
                var directories = Directory.GetDirectories(sourceDir);

                foreach (var dir in directories)
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    var relativePath = GetRelativePath(dir, sourceDir);
                    var targetSubDir = Path.Combine(targetDir, relativePath);

                    // 检查文件夹修改时间
                    if (IsItemOlderThanMinimumAge(dir, true))
                    {
                        if (!Directory.Exists(targetSubDir))
                        {
                            Directory.CreateDirectory(targetSubDir);
                        }

                        // 递归备份子目录
                        await BackupDirectoryAsync(dir, targetSubDir, cancellationToken);
                    }
                }

                // 获取所有文件
                var files = Directory.GetFiles(sourceDir);

                foreach (var file in files)
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    // 检查文件修改时间
                    if (IsItemOlderThanMinimumAge(file, false))
                    {
                        var relativePath = GetRelativePath(file, sourceDir);
                        var targetFile = Path.Combine(targetDir, relativePath);

                        await BackupFileAsync(file, targetFile, cancellationToken);
                    }
                }
            }
            catch (OperationCanceledException)
            {
                throw;
            }
            catch (Exception ex)
            {
                OnStatusChanged($"处理目录时出错: {sourceDir}, 错误: {ex.Message}");
                // 继续处理其他文件/目录
            }
        }

        private async Task BackupFileAsync(string sourceFile, string targetFile, CancellationToken cancellationToken)
        {
            try
            {
                var task = new BackupTask
                {
                    SourcePath = sourceFile,
                    TargetPath = targetFile,
                    FileSize = new FileInfo(sourceFile).Length,
                    StartTime = DateTime.Now,
                    Status = BackupStatus.Pending
                };

                // 添加到任务列表
                BackupTasks.Add(task);
                OnProgressUpdated();

                // 确保目标目录存在
                var targetDir = Path.GetDirectoryName(targetFile);
                if (!Directory.Exists(targetDir))
                {
                    Directory.CreateDirectory(targetDir);
                }

                task.Status = BackupStatus.InProgress;
                OnProgressUpdated();

                // 复制文件并显示进度
                using (var sourceStream = new FileStream(sourceFile, FileMode.Open, FileAccess.Read, FileShare.Read))
                using (var targetStream = new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.None))
                {
                    var buffer = new byte[8192];
                    int bytesRead;

                    while ((bytesRead = await sourceStream.ReadAsync(buffer, 0, buffer.Length, cancellationToken)) > 0)
                    {
                        await targetStream.WriteAsync(buffer, 0, bytesRead, cancellationToken);

                        // 更新进度
                        task.Transferred += bytesRead;
                        OnProgressUpdated();
                    }
                }

                task.Status = BackupStatus.Completed;
                OnProgressUpdated();
            }
            catch (OperationCanceledException)
            {
                var task = BackupTasks.Find(t => t.SourcePath == sourceFile);
                if (task != null)
                {
                    task.Status = BackupStatus.Canceled;
                    OnProgressUpdated();
                }
                throw;
            }
            catch (Exception ex)
            {
                var task = BackupTasks.Find(t => t.SourcePath == sourceFile);
                if (task != null)
                {
                    task.Status = BackupStatus.Error;
                    task.ErrorMessage = ex.Message;
                    OnProgressUpdated();
                }
            }
        }

        private bool IsItemOlderThanMinimumAge(string path, bool isDirectory)
        {
            try
            {
                DateTime lastModified;

                if (isDirectory)
                    lastModified = Directory.GetLastWriteTime(path);
                else
                    lastModified = File.GetLastWriteTime(path);

                var timeDifference = DateTime.Now - lastModified;
                return timeDifference.TotalSeconds > MinimumFileAgeSeconds;
            }
            catch (Exception ex)
            {
                OnStatusChanged($"检查文件/目录时间时出错: {path}, 错误: {ex.Message}");
                return false;
            }
        }

        private string GetRelativePath(string fullPath, string basePath)
        {
            if (!basePath.EndsWith(Path.DirectorySeparatorChar.ToString()))
                basePath += Path.DirectorySeparatorChar;

            Uri baseUri = new Uri(basePath);
            Uri fullUri = new Uri(fullPath);

            Uri relativeUri = baseUri.MakeRelativeUri(fullUri);
            return relativeUri.ToString().Replace("/", Path.DirectorySeparatorChar.ToString());
        }

        protected virtual void OnProgressUpdated()
        {
            ProgressUpdated?.Invoke(this, EventArgs.Empty);
        }

        protected virtual void OnStatusChanged(string status)
        {
            StatusChanged?.Invoke(this, status);
        }
    }

    /// <summary>
    /// 备份任务类
    /// </summary>
    public class BackupTask
    {
        public string SourcePath { get; set; }
        public string TargetPath { get; set; }
        public long FileSize { get; set; }
        public long Transferred { get; set; }
        public DateTime StartTime { get; set; }
        public BackupStatus Status { get; set; }
        public string ErrorMessage { get; set; }

        public double Progress => FileSize > 0 ? (double)Transferred / FileSize : 1.0;

        public double GetTransferSpeed()
        {
            TimeSpan elapsed = DateTime.Now - StartTime;
            if (elapsed.TotalSeconds < 0.1) return 0;
            return (Transferred / 1024.0) / elapsed.TotalSeconds;
        }

        public string StatusText
        {
            get
            {
                switch (Status)
                {
                    case BackupStatus.Pending:
                        return "准备中";
                    case BackupStatus.InProgress:
                        return "进行中";
                    case BackupStatus.Completed:
                        return "已完成";
                    case BackupStatus.Canceled:
                        return "已取消";
                    case BackupStatus.Error:
                        return string.IsNullOrEmpty(ErrorMessage) ? "错误" : $"错误: {ErrorMessage}";
                    default:
                        return Status.ToString();
                }
            }
        }
    }

    /// <summary>
    /// 备份状态枚举
    /// </summary>
    public enum BackupStatus
    {
        Pending,
        InProgress,
        Completed,
        Canceled,
        Error
    }

    /// <summary>
    /// 路径转文件名转换器
    /// </summary>
    [ValueConversion(typeof(string), typeof(string))]
    public class PathToNameConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value is string path)
            {
                return Path.GetFileName(path);
            }
            return value;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// 百分比转换器
    /// </summary>
    [ValueConversion(typeof(double), typeof(double))]
    public class PercentageConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value is double percentage)
            {
                return percentage * 100;
            }
            return value;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value is double percentage)
            {
                return percentage / 100;
            }
            return value;
        }
    }
}